package com.glsc.ngateway.platform.service.itflow.flowstrategy.cmdb.deviceStandardModify;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.glsc.ngateway.common.api.common.enums.DictConstant;
import com.glsc.ngateway.common.api.flowable.dto.FlowFormNewDeviceStandardDetailDto;
import com.glsc.ngateway.common.api.flowable.dto.task.doTaskParam.AbstractFlowSearchParamDto;
import com.glsc.ngateway.common.api.flowable.dto.task.formData.cmdb.DeviceStandardModifyTaskFormDto;
import com.glsc.ngateway.common.api.flowable.dto.task.formData.cmdb.domainDto.FlowFormDeviceStandardModifyDto;
import com.glsc.ngateway.common.api.platform.dto.user.PlatformUserDto;
import com.glsc.ngateway.common.base.converter.platform.FlowFormDeviceStandardModifyConverter;
import com.glsc.ngateway.common.base.converter.platform.FlowFormNewDeviceDiskStandardDetailConverter;
import com.glsc.ngateway.common.base.converter.platform.FlowFormNewDevicePartStandardDetailConverter;
import com.glsc.ngateway.common.base.converter.platform.FlowFormNewDeviceStandardDetailConverter;
import com.glsc.ngateway.common.base.domain.mysql.cmdb.CmdbCpuStandard;
import com.glsc.ngateway.common.base.domain.mysql.cmdb.CmdbMemoryStandard;
import com.glsc.ngateway.common.base.domain.mysql.gateway.platform.flow.cmdb.*;
import com.glsc.ngateway.common.base.enums.itflow.ITFlowEnum;
import com.glsc.ngateway.common.base.enums.itflow.ITFlowTaskEnum;
import com.glsc.ngateway.common.base.enums.itflow.ITFlowTaskParamEnum;
import com.glsc.ngateway.common.base.exception.PlatformException;
import com.glsc.ngateway.common.base.repo.mysql.gateway.platform.flow.cmdb.*;
import com.glsc.ngateway.platform.service.cmdb.CmdbCpuStandardService;
import com.glsc.ngateway.platform.service.cmdb.CmdbMemoryStandardService;
import com.glsc.ngateway.platform.service.cmdb.SequenceProductService;
import com.glsc.ngateway.platform.service.itflow.flowstrategy.AbstractItFlowStrategy;
import com.glsc.ngateway.platform.service.itflow.flowstrategy.cmdb.deviceStandardModify.taskPostHandler.IDeviceStandardModifyTaskPostHandlerAudit;
import com.glsc.ngateway.platform.utils.AssertOverride;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author liwei
 * @date 2023/8/2-15:22
 */
@Component
public class DeviceStandardModifyFlowStrategy extends AbstractItFlowStrategy<FlowFormDeviceStandardModifyDto, DeviceStandardModifyTaskFormDto> {
    private Map<String, IDeviceStandardModifyTaskPostHandlerAudit> taskPostHandlerMap;
    private HashMap<String, String> modifyTypeMap = new HashMap<>();
    private final String ADDTYPE = "0";
    private final String DELETETYPE = "1";
    private final String UPDATETYPE = "2";
    @Autowired
    private FlowFormDeviceStandardModifyRepo flowFormDeviceStandardModifyRepo;
    @Autowired
    private FlowFormNewDeviceStandardDetailRepo deviceStandardDetailRepo;
    @Autowired
    private FlowFormNewDeviceCpuStandardDetailRepo deviceCpuStandardDetailRepo;
    @Autowired
    private FlowFormNewDeviceMemoryStandardDetailRepo deviceMemoryStandardDetailRepo;
    @Autowired
    private FlowFormNewDeviceDiskStandardDetailRepo deviceDiskStandardDetailRepo;
    @Autowired
    private FlowFormNewDevicePartStandardDetailRepo devicePartStandardDetailRepo;
    @Autowired
    private SequenceProductService sequenceProductService;
    @Autowired
    private CmdbCpuStandardService cmdbCpuStandardService;
    @Autowired
    private CmdbMemoryStandardService cmdbMemoryStandardService;

    @Autowired
    public void setTaskPostHandlerMap(List<IDeviceStandardModifyTaskPostHandlerAudit> taskPostHandlerList) {
        this.taskPostHandlerMap = taskPostHandlerList.stream()
                .collect(Collectors.toMap(IDeviceStandardModifyTaskPostHandlerAudit::getTaskDefinitionKey, handler -> handler));
    }

    @Autowired
    private void setModifyTypeMap() {
        this.modifyTypeMap.put(ADDTYPE, "新增");
        this.modifyTypeMap.put(DELETETYPE, "删除");
        this.modifyTypeMap.put(UPDATETYPE, "更新");
    }

    @Override
    protected Map getTaskPassMap() {
        return taskPostHandlerMap;
    }

    @Override
    protected Map getTaskRejectMap() {
        return taskPostHandlerMap;
    }

    @Override
    public ITFlowEnum getFlowEnum() {
        return ITFlowEnum.CMDB_DEVICE_STANDARD_MODIFY;
    }

    @Override
    public List<String> pageProcessId(AbstractFlowSearchParamDto param, Pageable pageable) {
        return null;
    }

    @Override
    public DeviceStandardModifyTaskFormDto saveOrUpdateForm(@NotNull DeviceStandardModifyTaskFormDto flowableForm) throws Exception {
        if (StrUtil.isEmpty(flowableForm.getProcessId())) {
            throw PlatformException.error("没有流程processId,无法保存流程数据", false, false);
        }
        //保存流程主表单数据
        FlowFormDeviceStandardModify oldData = flowFormDeviceStandardModifyRepo.findByProcessId(flowableForm.getProcessId());
        if (Objects.nonNull(oldData)) {
            flowableForm.getFormMainData().setId(oldData.getId());
        }
        flowFormDeviceStandardModifyRepo.save(Objects.requireNonNull(FlowFormDeviceStandardModifyConverter.dto2Do(flowableForm.getFormMainData())));
        //操作类型
        String modifyType = flowableForm.getFormMainData().getModifyType();
        if (Objects.equals(modifyType, ADDTYPE)) {
            //保存新增的cpu/内存/硬盘/配件数据到流程表单子表。先删除已有processId的全部数据，再插入
            saveStandardList(flowableForm.getProcessId(), flowableForm, ADDTYPE);
        } else if (Objects.equals(modifyType, DELETETYPE)) {
            //业务类型是删除。先删除已有processId的全部数据，再插入
            saveStandardList(flowableForm.getProcessId(), flowableForm, DELETETYPE);
        } else if (Objects.equals(modifyType, UPDATETYPE)) {
            //业务类型是更新。先删除已有processId的全部数据，再插入
            saveStandardList(flowableForm.getProcessId(), flowableForm, UPDATETYPE);
        }
        return flowableForm;
    }

    @Override
    public DeviceStandardModifyTaskFormDto findFormByProcessId(String processId) {
        DeviceStandardModifyTaskFormDto flowableForm = new DeviceStandardModifyTaskFormDto();
        FlowFormDeviceStandardModify formMainDataDo = flowFormDeviceStandardModifyRepo.findByProcessId(processId);
        if (Objects.isNull(formMainDataDo)) {
            flowableForm.setFormMainData(new FlowFormDeviceStandardModifyDto());
        } else {
            flowableForm.setFormMainData(FlowFormDeviceStandardModifyConverter.do2Dto(formMainDataDo));
            if (Objects.equals(formMainDataDo.getModifyType(), ADDTYPE)) {
                //新增
                setFlowableStandardList(processId, flowableForm, formMainDataDo, ADDTYPE);
            } else if (Objects.equals(formMainDataDo.getModifyType(), DELETETYPE)) {
                //删除，从配件数据库里查到被删除的数据，返回给前端展示
                setFlowableStandardList(processId, flowableForm, formMainDataDo, DELETETYPE);
            } else if (Objects.equals(formMainDataDo.getModifyType(), UPDATETYPE)) {
                //更新，从配件数据库里查到被删除的数据，返回给前端展示
                setFlowableStandardList(processId, flowableForm, formMainDataDo, UPDATETYPE);
            }
        }
        return flowableForm;
    }

    /**
     * 从流程子表取数据返回给前端
     */
    private void setFlowableStandardList(String processId, DeviceStandardModifyTaskFormDto flowableForm, FlowFormDeviceStandardModify formMainDataDo, String modifyType) {
        //服务器
        List<FlowFormNewDeviceStandardDetail> deviceList = deviceStandardDetailRepo.findAllByprocessId(processId);
        //cpu
        List<FlowFormNewDeviceCpuStandardDetail> cpuList = deviceCpuStandardDetailRepo.findAllByprocessId(processId);
        //内存
        List<FlowFormNewDeviceMemoryStandardDetail> memoryList = deviceMemoryStandardDetailRepo.findAllByprocessId(processId);
        //磁盘
        List<FlowFormNewDeviceDiskStandardDetail> diskList = deviceDiskStandardDetailRepo.findAllByprocessId(processId);
        //配件
        List<FlowFormNewDevicePartStandardDetail> partList = devicePartStandardDetailRepo.findAllByprocessId(processId);

        if (CollectionUtil.isNotEmpty(deviceList)) {

            for (FlowFormNewDeviceStandardDetail detail : deviceList) {
                //处理关联cpu
                List<FlowFormNewDeviceCpuStandardDetail> deviceCpuList = cpuList.stream().filter(e -> e.getDeviceStandardCode().equals(detail.getDeviceStandardCodeFlow())).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(deviceCpuList)) {
                    detail.setCpuAmount(deviceCpuList.get(0).getCpuAmount());
                    detail.setCpuStandardCode(deviceCpuList.get(0).getCpuStandardCode());
                    detail.setCpuStandardName(deviceCpuList.get(0).getCpuStandardName());
                    detail.setCpuDeviceRelateId(deviceCpuList.get(0).getCpuDeviceRelateId());
                }
                //处理关联memory
                List<FlowFormNewDeviceMemoryStandardDetail> deviceMemoryList = memoryList.stream().filter(e -> e.getDeviceStandardCode().equals(detail.getDeviceStandardCodeFlow())).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(deviceMemoryList)) {
                    detail.setMemoryAmount(deviceMemoryList.get(0).getMemoryAmount());
                    detail.setMemoryStandardCode(deviceMemoryList.get(0).getMemoryStandardCode());
                    detail.setMemoryStandardName(deviceMemoryList.get(0).getMemoryStandardName());
                    detail.setMemoryDeviceRelateId(deviceMemoryList.get(0).getMemoryDeviceRelateId());
                }
                //处理关联disk
                List<FlowFormNewDeviceDiskStandardDetail> deviceDiskList = diskList.stream().filter(e -> e.getDeviceStandardCode().equals(detail.getDeviceStandardCodeFlow())).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(deviceDiskList)) {
                    detail.setDiskStandardRelate(deviceDiskList);
                }
                //处理关联part
                List<FlowFormNewDevicePartStandardDetail> devicePartList = partList.stream().filter(e -> e.getDeviceStandardCode().equals(detail.getDeviceStandardCodeFlow())).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(devicePartList)) {
                    detail.setPartStandardRelate(devicePartList);
                }
            }

            flowableForm.setDeviceStandardNewDataList(FlowFormNewDeviceStandardDetailConverter.do2Dto(deviceList));
        }
    }

    /**
     * 前端规格数据保存到流程子表
     *
     * @throws Exception
     */
    private void saveStandardList(String processId, DeviceStandardModifyTaskFormDto flowableForm, String modifyType) throws Exception {
        AssertOverride.notNull(flowableForm.getDeviceStandardNewDataList(), "设备规格异常：数据不能为空。");
        List<FlowFormNewDeviceStandardDetailDto> deviceStandardList = flowableForm.getDeviceStandardNewDataList();
        deviceStandardDetailRepo.deleteAll(deviceStandardDetailRepo.findAllByprocessId(processId));
        deviceCpuStandardDetailRepo.deleteAll(deviceCpuStandardDetailRepo.findAllByprocessId(processId));
        deviceMemoryStandardDetailRepo.deleteAll(deviceMemoryStandardDetailRepo.findAllByprocessId(processId));
        deviceDiskStandardDetailRepo.deleteAll(deviceDiskStandardDetailRepo.findAllByprocessId(processId));
        devicePartStandardDetailRepo.deleteAll(devicePartStandardDetailRepo.findAllByprocessId(processId));

        List<FlowFormNewDeviceCpuStandardDetail> cpuList = Lists.newArrayList();
        List<FlowFormNewDeviceMemoryStandardDetail> memoryList = Lists.newArrayList();
        List<FlowFormNewDeviceDiskStandardDetail> diskList = Lists.newArrayList();
        List<FlowFormNewDevicePartStandardDetail> partList = Lists.newArrayList();

        for (FlowFormNewDeviceStandardDetailDto detail : deviceStandardList) {
            detail.setId(null);
            detail.setProcessId(flowableForm.getProcessId());
            detail.setModifyType(modifyType);
            detail.setDeviceStandardCodeFlow(sequenceProductService.buildSequence(DictConstant.CMDB_DEVICE_FLOW_STANDARD));
            //cpu
            if (StrUtil.isNotEmpty(detail.getCpuStandardCode())){
                //又改为李伟10-16 16:06改之前的代码
                CmdbCpuStandard cpuStandard = cmdbCpuStandardService.findByStandardCode(detail.getCpuStandardCode());
                cpuList.add(FlowFormNewDeviceCpuStandardDetail.builder().cpuAmount(detail.getCpuAmount()).cpuDeviceRelateId(detail.getCpuDeviceRelateId()).cpuStandardCode(cpuStandard.getCpuStandardCode())
                        .cpuStandardName(cpuStandard.getName()).deviceStandardCode(detail.getDeviceStandardCodeFlow()).modifyType(modifyType).id(null).processId(flowableForm.getProcessId()).build());
            }
            //memory
            if (StrUtil.isNotEmpty(detail.getMemoryStandardCode())){
                CmdbMemoryStandard memoryStandard = cmdbMemoryStandardService.findByStandardCode(detail.getMemoryStandardCode());
                memoryList.add(FlowFormNewDeviceMemoryStandardDetail.builder().memoryAmount(detail.getMemoryAmount()).memoryDeviceRelateId(detail.getMemoryDeviceRelateId()).memoryStandardCode(memoryStandard.getMemoryStandardCode())
                        .memoryStandardName(memoryStandard.getName()).deviceStandardCode(detail.getDeviceStandardCodeFlow()).modifyType(modifyType).id(null).processId(flowableForm.getProcessId()).build());
            }
            //disk
            if (CollectionUtil.isNotEmpty(detail.getDiskStandardRelate())) {
                detail.getDiskStandardRelate().stream().map(e -> {
                    e.setId(null);
                    e.setProcessId(flowableForm.getProcessId());
                    e.setModifyType(modifyType);
                    e.setDeviceStandardCode(detail.getDeviceStandardCodeFlow());
                    return e;
                }).collect(Collectors.toList());
                diskList.addAll(FlowFormNewDeviceDiskStandardDetailConverter.dto2Do(detail.getDiskStandardRelate()));
            }
            //part
            if (CollectionUtil.isNotEmpty(detail.getPartStandardRelate())) {
                detail.getPartStandardRelate().stream().map(e -> {
                    e.setId(null);
                    e.setProcessId(flowableForm.getProcessId());
                    e.setModifyType(modifyType);
                    e.setDeviceStandardCode(detail.getDeviceStandardCodeFlow());
                    return e;
                }).collect(Collectors.toList());
                partList.addAll(FlowFormNewDevicePartStandardDetailConverter.dto2Do(detail.getPartStandardRelate()));
            }
        }

        if (CollectionUtil.isNotEmpty(deviceStandardList)) {
            deviceStandardDetailRepo.saveAll(FlowFormNewDeviceStandardDetailConverter.dto2Do(deviceStandardList));
        }

        if (CollectionUtil.isNotEmpty(cpuList)) {
            deviceCpuStandardDetailRepo.saveAll(cpuList);
        }

        if (CollectionUtil.isNotEmpty(memoryList)) {
            deviceMemoryStandardDetailRepo.saveAll(memoryList);
        }

        if (CollectionUtil.isNotEmpty(diskList)) {
            deviceDiskStandardDetailRepo.saveAll(diskList);
        }

        if (CollectionUtil.isNotEmpty(partList)) {
            devicePartStandardDetailRepo.saveAll(partList);
        }

    }

    /**
     * 流程节点，发起时动态指定节点处理人
     */
    @Override
    protected Map<String, List<String>> initDefaultTaskUserGroup(PlatformUserDto creator) throws PlatformException {
        Map<String, List<String>> taskAssignee = new HashMap<>(16);
        //1、发起人
        taskAssignee.put(ITFlowTaskParamEnum.CMDB_DEVICE_STANDARD_MODIFY_FLOW_BEGIN_TASK_ASSIGNMENTS.getName(), Arrays.asList(creator.getUsername()));
        //2、发起人确认
        taskAssignee.put(ITFlowTaskParamEnum.CMDB_DEVICE_STANDARD_MODIFY_FLOW_CREATOR_AUDIT_TASK_ASSIGNMENTS.getName(), Arrays.asList(creator.getUsername()));
        return taskAssignee;
    }

}
